package com.cq.hd.merchant.biz;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.entity.MerchantAppLoginUser;
import com.cq.hd.common.entity.MerchantUserInfo;
import com.cq.hd.common.enums.ResponseEnums;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.exception.BusinessException;
import com.cq.hd.common.response.Result;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.BeanUtils;
import com.cq.hd.common.utils.RedisUtil;
import com.cq.hd.common.utils.StringUtils;
import com.cq.hd.member.api.*;
import com.cq.hd.member.api.dto.*;
import com.cq.hd.member.api.vo.*;
import com.cq.hd.merchant.config.LockUtils;
import com.cq.hd.merchant.dto.MerchantBankCardUpdateDto;
import com.cq.hd.merchant.vo.BalanceAmtWithdrawalPreVo;
import com.cq.hd.merchant.vo.SubsidyMonthSettlePreVo;
import com.cq.hd.merchant.vo.WithdrawalPreVo;
import com.cq.hd.order.api.TbMonthSettleBillApi;
import com.cq.hd.order.api.TbOrderSettleBillApi;
import com.cq.hd.order.api.dto.OrderSettleBillDto;
import com.cq.hd.order.api.vo.MonthSettleBillVo;
import com.cq.hd.order.api.vo.OrderSettleBillVo;
import com.cq.hd.system.api.TbWithdrawalConfigApi;
import com.cq.hd.system.api.vo.WithdrawalConfigVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class MerchantBiz {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private TbMerchantApi merchantApi;

    @Autowired
    private TbBusinessMerchantApi businessMerchantApi;

    @Autowired
    private TbWithdrawalConfigApi withdrawalConfigApi;

    @Autowired
    private TbMerchantEnterApplyApi merchantEnterApplyApi;

    @Autowired
    private TbBusinessEnterApplyApi businessEnterApplyApi;

    @Autowired
    private TbOrderSettleBillApi orderSettleBillApi;

    @Autowired
    private SmsApi smsApi;

    @Autowired
    private TbMonthSettleBillApi tbMonthSettleBillApi;

    /**
     * 获取商户结算类型
     */
    public Integer getFinancialAccountType(Long merchantId) {
        MerchantVo merchantVo = merchantApi.getById(merchantId).unpack();
        if (merchantVo == null) {
            return FinancialAccountTypeEnum.SELF.getValue();
        }
        return merchantVo.getFinancialAccountType();
    }

    public MerchantUserInfo getMerchantInfo(MerchantAppLoginUser merchantAppLoginUser) {
        MerchantUserInfo merchantUserInfo = new MerchantUserInfo();
        // TODO 此处缓存，导致更新了商户信息后，再次调用这个接口还是旧的，如果删除了这个缓存，登录会失效，暂时先注释掉
//        String merchantInfoRedis = redisUtil.get(String.format(RedisKeyConstant.MERCHANT_INFO_KEY, merchantAppLoginUser.getMerchantId()));
//        if (!StringUtils.isNullOrEmpty(merchantInfoRedis)) {
//            merchantUserInfo = JSON.parseObject(merchantInfoRedis, MerchantUserInfo.class);
//            return merchantUserInfo;
//        }

        // 通过merchantId查询用户信息
        MerchantVo merchantVo = merchantApi.getById(merchantAppLoginUser.getMerchantId()).unpack();
        if (merchantVo == null || merchantVo.getState() == 2) {
            Throw.isBusinessException(ResponseEnums.USER_NOT_FOUND);
        }
        BeanUtils.copyProperties(merchantVo, merchantUserInfo);

        merchantUserInfo.setPwdSetState(!StringUtils.isBlank(merchantVo.getLoginPass()));

        return merchantUserInfo;
    }

    // 自有商户的商家关联的商户列表（不包含自己）
    public List<MerchantPageVo> listMyBusinessMerchant(Long merchantId) {
        MerchantVo merchantVo = merchantApi.getById(merchantId).unpack();
        if (merchantVo == null) {
            Throw.isBusinessException("商户不存在");
        }
        if (merchantVo.getMasterBusinessId() != null) {
            List<MerchantPageVo> merchantList = businessMerchantApi.listMerchantByBusinessId(merchantVo.getMasterBusinessId()).unpack();
            return merchantList.stream()
                    .filter(e -> !Objects.equals(e.getId(), merchantId))
                    .collect(Collectors.toList());
        }
        throw new BusinessException("暂无权限");
    }

    public Result<Boolean> updateCustomInfo(MerchantCustomUpdateDto merchantCustomUpdateDto) {
        return merchantApi.updateCustomInfo(merchantCustomUpdateDto);
    }

    public Result<Boolean> updatePwd(MerchantPwdUpdateDto merchantPwdUpdateDto) {
        return merchantApi.updatePwd(merchantPwdUpdateDto);
    }

    /**
     * 获取商户提现银行卡信息
     *
     * @param merchantId 商户id
     * @return 提现银行卡信息
     */
    public MerchantBankCardVo getMerchantBankCard(Long merchantId) {
        MerchantVo merchantVo = merchantApi.getById(merchantId).unpack();
        if (merchantVo == null) {
            Throw.isBusinessException("商户不存在");
        }
        return merchantApi.getBankCard(merchantId).unpack();
    }

    public Boolean updateMerchantBankCard(MerchantAppLoginUser merchantLoginUser, MerchantBankCardUpdateDto merchantBankCardUpdateDto) {
        merchantBankCardUpdateDto.setMerchantId(merchantLoginUser.getMerchantId());
        String mobile = merchantLoginUser.getMerchantUserInfo().getMobile();
        // 对手机号加锁
        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "updateMerchantBankCard:" + mobile);
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);
            // 判断短信验证码是否正确
            SmsVerifyDto smsVerifyDto = new SmsVerifyDto();
            smsVerifyDto.setCode(merchantBankCardUpdateDto.getSmsCode());
            smsVerifyDto.setMobile(mobile);
            smsVerifyDto.setType(SmsTypeEnum.SMS_UPDATE_MERCHANT_BANK_CARD.getValue());
            smsApi.verify(smsVerifyDto).isSuccess();
        } finally {
            LockUtils.unlock(lockKey);
        }
        MerchantBankCardDto merchantBankCardDto = BeanUtil.copyProperties(merchantBankCardUpdateDto, MerchantBankCardDto.class);
        merchantApi.updateBankCard(merchantBankCardDto).isSuccess();
        return true;
    }

    public Result<Boolean> updateShortName(MerchantAppLoginUser merchantLoginUser, String merchantShortName) {
        MerchantUpdateDto merchantUpdateDto = new MerchantUpdateDto();
        merchantUpdateDto.setId(merchantLoginUser.getMerchantId());
        merchantUpdateDto.setMerchantShortName(merchantShortName);
        merchantUpdateDto.setUpdateTime(LocalDateTime.now());
        return merchantApi.updateMerchant(merchantUpdateDto);
    }

    public Result<Boolean> updateAvatar(MerchantAppLoginUser merchantLoginUser, String avatar) {
        MerchantUpdateDto merchantUpdateDto = new MerchantUpdateDto();
        merchantUpdateDto.setId(merchantLoginUser.getMerchantId());
        merchantUpdateDto.setAvatar(avatar);
        merchantUpdateDto.setUpdateTime(LocalDateTime.now());
        return merchantApi.updateMerchant(merchantUpdateDto);
    }

    // 结算池商户本金提现-预览页
    public BalanceAmtWithdrawalPreVo balanceAmtWithdrawalPre(Long merchantId) {
        MerchantVo merchantVo = merchantApi.getById(merchantId).unpack();
        if (merchantVo == null) {
            Throw.isBusinessException("获取商户信息失败");
        }
        WithdrawalConfigVo withdrawalConfigVo = withdrawalConfigApi.details(WithdrawalTypeEnum.MERCHANT_AMT.getValue(), FinancialAccountTypeEnum.PLATFORM.getValue()).unpack();
        if (withdrawalConfigVo == null) {
            log.error("申请提现失败，未配置提现参数，withdrawalType：{}, financialAccountType:{}", WithdrawalTypeEnum.MERCHANT_AMT.getValue(), FinancialAccountTypeEnum.PLATFORM.getValue());
            Throw.isBusinessException("申请提现失败，请联系客服");
        }
        return new BalanceAmtWithdrawalPreVo(merchantVo.getBalanceAmt(), withdrawalConfigVo.getDescription());
    }

    public WithdrawalPreVo preWithdrawal(MerchantAppLoginUser merchantAppLoginUser) {
        // 商户本金
        BigDecimal merchantAmt = BigDecimal.ZERO;
        // 商户补贴
        BigDecimal merchantSubsidy = BigDecimal.ZERO;
        // 商户本金提现说明
        String merchantAmtDescription = "";
        // 商户补贴提现说明
        String merchantSubsidyDescription = "";
        // 持卡人姓名
        String cardName = "";
        // 银行卡号
        String cardNo = "";
        // 开户银行
        String bankName = "";

        MerchantVo merchantVo = merchantApi.getById(merchantAppLoginUser.getMerchantId()).unpack();
        if (merchantVo != null) {
            merchantAmt = merchantVo.getBalanceAmt();
            merchantSubsidy = merchantVo.getSubsidyAmt();

            BigDecimal totalWaitTradeAmt = BigDecimal.ZERO;
            OrderSettleBillDto orderSettleBillDto = new OrderSettleBillDto();
            orderSettleBillDto.setMerchantId(merchantAppLoginUser.getMerchantId());
            orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue());
            orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.FAIL.getValue(), OrderSettleBillTradeStateEnum.WAIT.getValue()));
            List<OrderSettleBillVo> orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
            if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
                for (OrderSettleBillVo orderSettleBillVo : orderSettleBillVos) {
                    orderSettleBillApi.transactAmt(orderSettleBillVo);
                }

                orderSettleBillDto = new OrderSettleBillDto();
                orderSettleBillDto.setMerchantId(merchantAppLoginUser.getMerchantId());
                orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.SUBSIDY_AMT.getValue());
                orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.FAIL.getValue(), OrderSettleBillTradeStateEnum.WAIT.getValue()));
                orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
                if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
                    for (OrderSettleBillVo orderSettleBillVo : orderSettleBillVos) {
                        totalWaitTradeAmt = totalWaitTradeAmt.add(orderSettleBillVo.getTradeAmt());
                    }
                }
            }

            merchantSubsidy = merchantSubsidy.subtract(totalWaitTradeAmt);
            if(merchantSubsidy.compareTo(BigDecimal.ZERO) < 0){
                merchantSubsidy = BigDecimal.ZERO;
            }

            String openid = merchantVo.getOpenid();
            // 查询入驻成功记录
            MerchantEnterApplyVo enterInfoByOpenid = merchantEnterApplyApi.getSuccessEnterInfoByOpenid(openid).unpack();
            if (enterInfoByOpenid != null) {
                cardName = enterInfoByOpenid.getCardName();
                cardNo = enterInfoByOpenid.getCardNo();
                String bankCode = enterInfoByOpenid.getBankCode();
                if (!StringUtils.isBlank(bankCode)) {
                    HfBankIdEnum hfBankIdEnum = HfBankIdEnum.typeOfValue(bankCode);
                    if (hfBankIdEnum != null) {
                        bankName = hfBankIdEnum.getName();
                    }
                }
            } else {
                // 查询商家入驻成功记录
                BusinessEnterApplyDetailVo businessEnterApplyDetailVo = businessEnterApplyApi.getSuccessEnterInfoByOpenid(openid).unpack();
                if (businessEnterApplyDetailVo != null) {
                    cardName = businessEnterApplyDetailVo.getCardName();
                    cardNo = businessEnterApplyDetailVo.getCardNo();
                    String bankCode = businessEnterApplyDetailVo.getBankCode();
                    if (!StringUtils.isBlank(bankCode)) {
                        HfBankIdEnum hfBankIdEnum = HfBankIdEnum.typeOfValue(bankCode);
                        if (hfBankIdEnum != null) {
                            bankName = hfBankIdEnum.getName();
                        }
                    }
                }
            }
        }

        Integer financialAccountType = FinancialAccountTypeEnum.SELF.getValue();
        if (merchantVo != null) {
            financialAccountType = merchantVo.getFinancialAccountType();
        }

        // 查询提现说明
        WithdrawalConfigVo withdrawalConfigVo = withdrawalConfigApi.details(WithdrawalConfigUserTypeEnum.MERCHANT_AMT.getValue(), financialAccountType).unpack();
        if (withdrawalConfigVo != null) {
            merchantAmtDescription = withdrawalConfigVo.getDescription();
        }

        withdrawalConfigVo = withdrawalConfigApi.details(WithdrawalConfigUserTypeEnum.MERCHANT_SUBSIDY.getValue(), financialAccountType).unpack();
        if (withdrawalConfigVo != null) {
            merchantSubsidyDescription = withdrawalConfigVo.getDescription();
        }

        WithdrawalPreVo withdrawalPreVo = new WithdrawalPreVo();
        withdrawalPreVo.setMerchantAmt(merchantAmt);
        withdrawalPreVo.setMerchantSubsidy(merchantSubsidy);
        withdrawalPreVo.setMerchantAmtDescription(merchantAmtDescription);
        withdrawalPreVo.setMerchantSubsidyDescription(merchantSubsidyDescription);
        withdrawalPreVo.setCardName(cardName);
        withdrawalPreVo.setCardNo(cardNo);
        withdrawalPreVo.setBankName(bankName);

        return withdrawalPreVo;
    }

    /**
     * 补贴提现：月度结算单
     */
    public SubsidyMonthSettlePreVo subsidyMonthSettleList(Long merchantId, int financialAccountType) {
        SubsidyMonthSettlePreVo subsidyMonthSettlePreVo = new SubsidyMonthSettlePreVo();

        // 月度结算单
        List<MonthSettleBillVo> monthSettleBillVos = tbMonthSettleBillApi.getMerchantWaitMonthSettleBill(merchantId, MonthSettleBillTypeEnum.SUBSIDY_AMT.getValue()).unpack();
        Map<Long, List<MonthSettleBillVo>> groupedByBusinessId = monthSettleBillVos.stream()
                .collect(Collectors.groupingBy(MonthSettleBillVo::getBusinessId));
        List<List<MonthSettleBillVo>> groupedList = new ArrayList<>(groupedByBusinessId.values());
        subsidyMonthSettlePreVo.setMonthSettleBills(groupedList);

        // 提现说明
        WithdrawalConfigVo withdrawalConfigVo = withdrawalConfigApi.details(WithdrawalConfigUserTypeEnum.MERCHANT_SUBSIDY.getValue(), financialAccountType).unpack();
        if (withdrawalConfigVo != null) {
            subsidyMonthSettlePreVo.setDescription(withdrawalConfigVo.getDescription());
        }

        return subsidyMonthSettlePreVo;
    }
}
